import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

public class GomokuGame1 {
    public static void main(String[] args) {
        new GomokuGame1();
    }

    public GomokuGame1() {
        JFrame frame = new JFrame("五子棋（含禁手规则）");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 850);
        frame.setLocationRelativeTo(null);

        GomokuPanel1 panel = new GomokuPanel1();
        frame.add(panel, BorderLayout.CENTER);

        // 添加底部面板和按钮
        JPanel bottomPanel = new JPanel();
        JButton resetButton = new JButton("重新开始");
        resetButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                panel.initializeGame();
            }
        });
        bottomPanel.add(resetButton);

        // 添加禁手规则说明按钮
        JButton ruleButton = new JButton("禁手规则说明");
        ruleButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame,
                        "禁手规则（仅对黑子有效）:\n" +
                                "1. 三三禁手：黑子一子落下同时形成两个或两个以上的活三\n" +
                                "2. 四四禁手：黑子一子落下同时形成两个或两个以上的四\n" +
                                "3. 长连禁手：黑子一子落下形成六个或六个以上的连续棋子\n" +
                                "违反以上任何禁手规则，黑子判负",
                        "禁手规则说明", JOptionPane.INFORMATION_MESSAGE);
            }
        });
        bottomPanel.add(ruleButton);

        frame.add(bottomPanel, BorderLayout.SOUTH);
        frame.setVisible(true);
    }
}

class GomokuPanel1 extends JPanel {
    private static final int BOARD_SIZE = 15;
    private static final int CELL_SIZE = 40;
    private static final int MARGIN = 50;
    private static final int PIECE_SIZE = 36;

    private int[][] board; // 0: 空, 1: 黑子, 2: 白子
    private boolean blackTurn;
    private boolean gameOver;
    private boolean forbiddenMove; // 标记是否为禁手

    public GomokuPanel1() {
        initializeGame();

        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (gameOver) {
                    return;
                }

                int x = e.getX();
                int y = e.getY();

                int col = (x - MARGIN + CELL_SIZE / 2) / CELL_SIZE;
                int row = (y - MARGIN + CELL_SIZE / 2) / CELL_SIZE;

                if (row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == 0) {
                    // 尝试落子
                    board[row][col] = blackTurn ? 1 : 2;

                    // 检查禁手（仅对黑子有效）
                    if (blackTurn) {
                        forbiddenMove = checkForbiddenMove(row, col);
                        if (forbiddenMove) {
                            gameOver = true;
                            JOptionPane.showMessageDialog(null, "黑子违反禁手规则！白子获胜！");
                            repaint();
                            return;
                        }
                    }

                    // 检查胜利
                    if (checkWin(row, col)) {
                        gameOver = true;
                        String winner = blackTurn ? "黑子" : "白子";
                        JOptionPane.showMessageDialog(null, winner + "获胜！");
                    } else {
                        blackTurn = !blackTurn;
                    }

                    repaint();
                }
            }
        });
    }

    // 初始化游戏
    public void initializeGame() {
        board = new int[BOARD_SIZE][BOARD_SIZE];
        blackTurn = true;
        gameOver = false;
        forbiddenMove = false;
        repaint();
    }

    // 检查禁手规则（仅对黑子有效）
    private boolean checkForbiddenMove(int row, int col) {
        // 长连禁手（六子或以上）
        if (checkOverline(row, col)) {
            return true;
        }

        // 检查三三禁手和四四禁手
        int threeCount = 0;
        int fourCount = 0;

        // 检查8个方向（实际上只需要检查4个方向，因为对称）
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};

        for (int[] dir : directions) {
            LineInfo info = countLine(row, col, dir[0], dir[1]);

            if (info.openFour) {
                fourCount++;
            } else if (info.three) {
                threeCount++;
            }

            // 检查对称方向
            LineInfo oppositeInfo = countLine(row, col, -dir[0], -dir[1]);
            if (oppositeInfo.openFour) {
                fourCount++;
            } else if (oppositeInfo.three) {
                threeCount++;
            }
        }

        // 三三禁手
        if (threeCount >= 2) {
            return true;
        }

        // 四四禁手
        if (fourCount >= 2) {
            return true;
        }

        return false;
    }

    // 检查长连禁手（六子或以上）
    private boolean checkOverline(int row, int col) {
        int[][] directions = {{0,1}, {1,0}, {1,1}, {1,-1}};

        for (int[] dir : directions) {
            int count = countConsecutive(row, col, dir[0], dir[1], 1);
            if (count >= 5) { // 因为countConsecutive已经包含当前子
                return true;
            }
        }

        return false;
    }

    // 检查一条线上的棋型
    private LineInfo countLine(int row, int col, int dRow, int dCol) {
        LineInfo info = new LineInfo();
        int player = board[row][col];
        int emptyCount = 0;
        List<Integer> sequence = new ArrayList<>();

        // 向一个方向扫描
        int r = row - 4 * dRow;
        int c = col - 4 * dCol;

        for (int i = 0; i < 9; i++) {
            if (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE) {
                sequence.add(board[r][c]);
            } else {
                sequence.add(-1); // 边界外视为障碍
            }
            r += dRow;
            c += dCol;
        }

        // 检查五子连珠（已经由checkWin处理）

        // 检查活四：_XXXX_
        if (sequence.get(4) == player) {
            if (sequence.get(3) == player && sequence.get(5) == player &&
                    sequence.get(2) == player && sequence.get(6) == 0 &&
                    sequence.get(1) == 0 && sequence.get(7) == 0) {
                info.openFour = true;
            }
            // 其他四的情况...
        }

        // 检查活三：_XXX_
        if (sequence.get(4) == player) {
            if (sequence.get(3) == player && sequence.get(5) == player &&
                    sequence.get(2) == 0 && sequence.get(6) == 0) {
                info.three = true;
            }
            // 其他三的情况...
        }

        return info;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        // 绘制棋盘背景
        g.setColor(new Color(220, 179, 92));
        g.fillRect(0, 0, getWidth(), getHeight());

        // 绘制棋盘网格
        g.setColor(Color.BLACK);
        for (int i = 0; i < BOARD_SIZE; i++) {
            g.drawLine(MARGIN, MARGIN + i * CELL_SIZE,
                    MARGIN + (BOARD_SIZE - 1) * CELL_SIZE, MARGIN + i * CELL_SIZE);
            g.drawLine(MARGIN + i * CELL_SIZE, MARGIN,
                    MARGIN + i * CELL_SIZE, MARGIN + (BOARD_SIZE - 1) * CELL_SIZE);
        }

        // 绘制棋盘上的五个小圆点
        int dotSize = 8;
        int[] dots = {3, 7, 11};
        for (int row : dots) {
            for (int col : dots) {
                if ((row == 7 && col == 7) || (row == 3 && col == 3) ||
                        (row == 3 && col == 11) || (row == 11 && col == 3) ||
                        (row == 11 && col == 11)) {
                    g.fillOval(MARGIN + col * CELL_SIZE - dotSize / 2,
                            MARGIN + row * CELL_SIZE - dotSize / 2,
                            dotSize, dotSize);
                }
            }
        }

        // 绘制棋子
        for (int row = 0; row < BOARD_SIZE; row++) {
            for (int col = 0; col < BOARD_SIZE; col++) {
                if (board[row][col] == 1) { // 黑子
                    g.setColor(Color.BLACK);
                    g.fillOval(MARGIN + col * CELL_SIZE - PIECE_SIZE / 2,
                            MARGIN + row * CELL_SIZE - PIECE_SIZE / 2,
                            PIECE_SIZE, PIECE_SIZE);
                } else if (board[row][col] == 2) { // 白子
                    g.setColor(Color.WHITE);
                    g.fillOval(MARGIN + col * CELL_SIZE - PIECE_SIZE / 2,
                            MARGIN + row * CELL_SIZE - PIECE_SIZE / 2,
                            PIECE_SIZE, PIECE_SIZE);
                    g.setColor(Color.BLACK);
                    g.drawOval(MARGIN + col * CELL_SIZE - PIECE_SIZE / 2,
                            MARGIN + row * CELL_SIZE - PIECE_SIZE / 2,
                            PIECE_SIZE, PIECE_SIZE);
                }
            }
        }

        // 显示当前回合
        g.setColor(Color.BLACK);
        g.setFont(new Font("Arial", Font.BOLD, 20));
        String turn = blackTurn ? "黑子回合（受禁手限制）" : "白子回合";
        g.drawString(turn, MARGIN, MARGIN + BOARD_SIZE * CELL_SIZE + 30);

        // 如果游戏结束，显示游戏结束提示
        if (gameOver) {
            g.setColor(Color.RED);
            g.setFont(new Font("Arial", Font.BOLD, 30));
            String message = forbiddenMove ? "黑子禁手！白子胜！" : "游戏结束";
            g.drawString(message, MARGIN + 100, MARGIN + BOARD_SIZE * CELL_SIZE + 70);
        }
    }

    // 检查是否获胜
    private boolean checkWin(int row, int col) {
        int player = board[row][col];

        // 检查水平方向
        if (countConsecutive(row, col, 0, 1, player) >= 5) return true;
        // 检查垂直方向
        if (countConsecutive(row, col, 1, 0, player) >= 5) return true;
        // 检查对角线方向（左上到右下）
        if (countConsecutive(row, col, 1, 1, player) >= 5) return true;
        // 检查对角线方向（右上到左下）
        if (countConsecutive(row, col, 1, -1, player) >= 5) return true;

        return false;
    }

    // 计算连续相同棋子的数量
    private int countConsecutive(int row, int col, int dRow, int dCol, int player) {
        int count = 1;

        // 正向检查
        count += countDirection(row, col, dRow, dCol, player);
        // 反向检查
        count += countDirection(row, col, -dRow, -dCol, player);

        return count;
    }

    // 向指定方向计数连续相同棋子
    private int countDirection(int row, int col, int dRow, int dCol, int player) {
        int count = 0;
        int r = row + dRow;
        int c = col + dCol;

        while (r >= 0 && r < BOARD_SIZE && c >= 0 && c < BOARD_SIZE && board[r][c] == player) {
            count++;
            r += dRow;
            c += dCol;
        }

        return count;
    }

    // 用于存储棋型信息的内部类
    private class LineInfo {
        boolean openFour = false; // 活四
        boolean three = false;    // 活三
    }
}